_Pragma("once");

#include <string>

#include "common.h"
#include "SocketCommunicator.h"
#include "SingletonTemplate.h"
#include "ConnectionStatus.h"

#include "ConfigManager.h"
#include "INetwork.h"
#include "OfflineReason.h"

constexpr std::size_t MAX_RECEIVE_BUFFER_SIZE = 128*1024; //128KB

class CommandParser;
class NetworkManager;
class NetworkListener;

class CommandDispatcher : public WithPoolWorkable<CommandDispatcher, NetworkString, NetworkString*> {
    using super = WithPoolWorkable<CommandDispatcher, NetworkString, NetworkString*>;

    friend class SingletonTemplate<CommandDispatcher>;

    static constexpr int32_t MAX_RECONNECT = 4;

public:
    /** Default destructor */
    ~CommandDispatcher();

    bool initial() {
        bool result = connect(true);
        if (!result) {
            close(true);
        }
        return true;
    }


    void resetAddressInfo(const IpAddressInfo& serverAddress) {
        ipAddressInfo = serverAddress;
        memset(&msockaddr, 0, sizeof(msockaddr));
        memset(&mtestSockaddr, 0, sizeof(mtestSockaddr));
    }


    bool uninitial() {

        return close(false);
    }


    bool connect(const bool notify);

    bool close(const bool notify);



    bool processPoolItem(super::PointType  element);

    void parseCommandExecute(NetworkString& data);

    void send(const NetworkString& data);

    bool notifyForReconnect(){
        return msocket.close();
    }

    ssize_t recv(NetworkString& buffer, const size_t beginIndex);

    ConnectionStatus getConnectionStatus(void){
        return mstatus;
    }

    bool testNetwork();
    OfflineReason analysisOfflineReason();

    std::string mlastCommandResponse;

    std::vector<NetworkListener*> mnetworkListeners;

    volatile uint32_t mserverReady = 0;

protected:
    /** Default constructor */
    CommandDispatcher();


    void parseReceivedData();

    ssize_t sendInternal(const NetworkString& data) {
        ssize_t ret = msocket.send(data);

        if (0 < ret) {
            LOG_TO(BizLogHandle, UsedLogger::INFO,  "send command to server:[%s],sent bytes:%zd", data.data(), ret);
        }

//        if (0 >= ret && OfflineReason::ONLINE == mofflineReason) {
//            analysisOfflineReason();
//        }

        return ret;
    }


    super::PoolType pool;
    INetwork* mpCurrentNetwork;

    volatile ConnectionStatus mstatus;

    CommandParser& mcommandParser;

    IpAddressInfo ipAddressInfo{"192.168.1.92", 1983};//47.101.55.205
    sockaddr_in msockaddr;
    SocketCommunicator msocket;

    IpAddressInfo mtestIpAddressInfo{"www.baidu.com", 80};
    sockaddr_in mtestSockaddr;
    SocketCommunicator mtestSocket;

    OfflineReason mofflineReason = OfflineReason::ONLINE;

    NetworkString mreceiveBuffer;
    NetworkString::size_type mreadIndex;
    int32_t mreadedBytes;

    NetworkManager& mnetworkManager;

    int32_t mretryCount = MAX_RECONNECT;

};


using CommandDispatcherSingleton = SingletonTemplate<CommandDispatcher>;
